package gin

// 这是注解路由完整版的!!
/*
import (
	"bytes"
	"context"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"gitee.com/gopher2011/function/gast"
	"gitee.com/gopher2011/function/gdoc"
	"gitee.com/gopher2011/function/gerror"
	"gitee.com/gopher2011/function/glog"
	"gitee.com/gopher2011/function/msg"
	"github.com/go-playground/validator/v10"
	"go/ast"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"sync"
	"text/template"
	"time"
)

const (
	getRouter = "./router.txt"
)

type (
	APIFunc func(*Context) interface{}
	ErrorFunc  func(interface{}) //错误设置
)

type (
	//参数类型描述
	parma struct {
		Pkg    string //包名
		Type   string //类型
		Import string //import包
	}

	// 生成的注解路由
	annotation struct {
		RouterPath string
		Note       string // 注释
		Methods    []string
	}

	// 路由规则列表
	routerRule struct {
		Annotation     annotation
		HandleFuncName string
	}

	genInfo struct {
		List []routerRule
		Tm  int64 // timeout
	}

)

var (
	typeOfError = reflect.TypeOf((*error)(nil)).Elem()
	routeRegex = regexp.MustCompile(`@Router\s+(\S+)(?:\s+\[(\S+)\])?`)
	mu sync.Mutex
	mp sync.Map
	once sync.Once
	info genInfo
	infoCfg genInfo

	genTemp = `
	package {{.PkgName}}
	
	import (
		"github.com/gopher2011/gin"
	)
	
	func init() {
		gin.SetVersion({{.Tm}})
		{{range .List}}gin.AddGenOne("{{.HandleFuncName}}", "{{.GenComment.RouterPath}}", []string{ {{GetStringList .GenComment.Methods}} })
		{{end}} }
	`
)

// 获取当前项目所在地址
func currentPath() string {
	dir, _ := os.Executable()
	exPath := filepath.Dir(dir)
	return exPath
}

//功能：序列化
func encode(data interface{})([]byte, error){
	buf := bytes.NewBuffer(nil)
	enc := gob.NewEncoder(buf)
	err := enc.Encode(data)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
// 反序列化
func decode(data []byte,to interface{}) error{
	buf := bytes.NewBuffer(data)
	dec := gob.NewDecoder(buf)
	return dec.Decode(to)
}

// buildDir 创建目录
func buildDir(absDir string) error {
	return os.MkdirAll(path.Dir(absDir), os.ModePerm) //生成多级目录
}


//func init(){
//	data,err := ioutil.ReadFile(path.Join(currentPath(),getRouter))
//	if err == nil {
//		decode(data,&infoCfg)
//	}
//	//fmt.Println(infoCfg.List)
//}

// 添加路由
// 参数<handleFuncName>是路由处理函数的名称
// <routerPath>是具体的路由 url 路径
// <methods>是具体的请求方法
func AddGenOne(handleFuncName, routerPath string, methods []string) {
	mu.Lock()
	defer mu.Unlock()
	info.List = append(info.List, routerRule{
		HandleFuncName: handleFuncName,
		Annotation: annotation{
			RouterPath: routerPath,
			Methods:    methods,
		},
	})
}


func checkOnceAdd(handleFuncName, routerPath string, methods []string) {
	once.Do(func() {
		mu.Lock()
		defer mu.Unlock()
		info.Tm = time.Now().Unix()
		info.List = []routerRule{} // reset
	})
	AddGenOne(handleFuncName, routerPath, methods)
}

func SetVersion(tm int64) {
	mu.Lock()
	defer mu.Unlock()
	info.Tm = tm
}

// GetStringList format string
func GetStringList(list []string) string {
	return `"` + strings.Join(list, `","`) + `"`
}

func getPkgName(dir string) string {
	dir = strings.Replace(dir, "\\", "/", -1)
	dir = strings.TrimRight(dir, "/")

	var pkgName string
	list := strings.Split(dir, "/")
	if len(list) > 0 {
		pkgName = list[len(list)-1]
	}

	if len(pkgName) == 0 || pkgName == "." {
		list = strings.Split(currentPath(), "/")
		if len(list) > 0 {
			pkgName = list[len(list)-1]
		}
	}
	return pkgName
}

func genCode(outDir, modFile string) bool {
	info.Tm = time.Now().Unix()
	if len(outDir) == 0 {
		outDir = modFile + "/routers/"
	}
	pkgName := getPkgName(outDir)
	data := struct {
		genInfo
		PkgName string
	}{
		genInfo: info,
		PkgName: pkgName,
	}

	tmpl, err := template.New("gen_out").Funcs(template.FuncMap{"GetStringList": GetStringList}).Parse(genTemp)
	if err != nil {
		panic(err)
	}
	var buf bytes.Buffer
	tmpl.Execute(&buf, data)
	f, err := os.Create(outDir + "gen_router.go")
	if err != nil {
		return false
	}
	defer f.Close()
	f.Write(buf.Bytes())

	// format
	exec.Command("gofmt", "-l", "-w", outDir).Output()
	return true
}

func genOutPut(outDir, modFile string) {
	mu.Lock()
	defer mu.Unlock()
	b := genCode(outDir, modFile) // gen .go file
	info.Tm = time.Now().Unix()
	data, _ := encode(&info) // gob serialize 序列化
	path := path.Join(currentPath(), getRouter)
	if !b {
		buildDir(path)
	}
	f, err := os.Create(path)
	if err != nil {
		return
	}
	defer f.Close()
	f.Write(data)
}

func getInfo() map[string][]routerRule {
	mu.Lock()
	defer mu.Unlock()

	tmp := info
	if infoCfg.Tm > tmp.Tm { // config to update more than coding
		tmp = infoCfg
	}

	mp := make(map[string][]routerRule, len(tmp.List))
	for _, v := range tmp.List {
		k := v
		mp[k.HandleFuncName] = append(mp[k.HandleFuncName], k)
	}
	return mp
}

func buildRelativePath(prefix, routerPath string) string {
	if strings.HasSuffix(prefix, "/") {
		if strings.HasPrefix(routerPath, "/") {
			return prefix + strings.TrimPrefix(routerPath, "/")
		}
		return prefix + routerPath
	}
	if strings.HasPrefix(routerPath, "/") {
		return prefix + routerPath
	}
	return prefix + "/" + routerPath
}

// 对象调用前后执行中间件参数
type BeforeAfter struct {
	C        *Context
	FuncName string      // 函数名
	Param    interface{} // 调用前的请求参数
	Response interface{} // 调用后的返回数据
	Error    error
	Ctx      context.Context // 占位参数，可用于存储其他参数，前后连接可用
}

// 对象调用前后执行中间件(支持总的跟对象单独添加)
type Hook interface {
	Before(r *BeforeAfter) bool
	After(r *BeforeAfter) bool
}

type RespBody struct {
	State bool        `json:"state"`
	Code  int         `json:"code,omitempty"`
	Error string      `json:"error,omitempty"`
	Data  interface{} `json:"data,omitempty"`
}

type (
	DefaultBeforeAfter struct {}
	timeTrace struct{}
)
// call之前调用
func (d *DefaultBeforeAfter)Before(r *BeforeAfter)bool{
	r.Ctx = context.WithValue(r.Ctx,timeTrace{},time.Now())
	return true
}
// call之后调用
func (d *DefaultBeforeAfter)After(r *BeforeAfter)bool{
	begin := (r.Ctx.Value(timeTrace{})).(time.Time)
	now := time.Now()
	log.Println(fmt.Sprintf("[middleware] call[%v] [%v]", r.FuncName, now.Sub(begin)))
	msg := RespBody{}
	if r.Error != nil {
		msg = errorMsg(r.Error.Error())
	}
	msg.Data = r.Response
	r.Param = msg // 设置resp 结果
	return true
}

func errorMsg(errorCode string) (msg RespBody) {
	msg.State = false
	msg.Code = codeId(errorCode)
	msg.Error = errorCode
	return
}

func codeId(codeStr string)int{
	v,ok := mp.Load(codeStr)
	if ok {
		return v.(int)
	}
	return -1
}

type Base struct {
	beforeAfter Hook
	apiFunc     APIFunc
	errorFunc   ErrorFunc
	apiType     reflect.Type
	outPath     string // output path.输出目录
	isBigCamel  bool   // 大驼峰命名规则
	isDev       bool   // 是否是开发者模式
	isOutDoc    bool
}

// Dev set build is development
func (b *Base) Dev(isDev bool) {
	b.isDev = isDev
}

func (b *Base) SetRecover(err func(interface{})) {
	b.errorFunc = err
}

// Default new op obj
func DefaultBase() *Base {
	b := new(Base)
	b.Model(func(c *Context) interface{} {
		return c
	})
	b.Dev(true)
	return b
}

func NewBase(opts ...Option)*Base{
	b := DefaultBase()

	//for _, v := range opts {
	//	v.apply(b)
	//}
	//b.SetRecover(func(err interface{}) {
	//	glog.Error(err)
	//})
	return b
}

// Model use custom context
func (b *Base) Model(middleware APIFunc) *Base {
	if middleware == nil {
		middleware = func(c *Context) interface{} {
			return c
		}
	}
	b.apiFunc = middleware // save callback
	rt := reflect.TypeOf(middleware(&Context{}))

	if rt == nil || rt.Kind() != reflect.Ptr {
		panic("need pointer")
	}
	b.apiType = rt
	return b
}

func (engine *Engine)New()*Base{
	b := new(Base)
	b.Model(func(c *Context) interface{} {
		return c
	})
	b.Dev(true)
	return b
}

type Option interface {
	apply(*Base)
}

type optionFunc func(*Base)

func (f optionFunc)apply( base *Base){
	f(base)
}

// Register 将结构体对象注册到当前路由中!
func (b *Base) Register(router IRoute, cList []interface{}) bool {
	if b.isDev {
		b.tryRegister(router, cList)
	}
	return b.register(router, cList...)
}

func (b *Base) BasePath(router IRoute) string {
	switch r := router.(type) {
	case *RouterGroup:
		return r.BasePath()
	case *Engine:
		return r.BasePath()
	}
	return ""
}

// checkHandlerFunc 判断是否匹配规则,返回参数个数
func (b *Base) checkHandlerFunc(typ reflect.Type, isObj bool) (int, bool) {
	offset := 0
	if isObj {
		offset = 1
	}
	num := typ.NumIn() - offset
	if num == 1 || num == 2 { //参数检查
		ctxType := typ.In(0 + offset)

		if ctxType == reflect.TypeOf(&Context{}) {//gin默认的方法
			return num, true
		}

		if ctxType == b.apiType {// 自定义的context
			return num, true
		}

		if b.apiType.ConvertibleTo(ctxType) {//如果是接口
			return num, true
		}
	}
	return num, false
}

func isParma(f *ast.FieldList, imports map[string]string, objPkg string, n int) (p *parma) {
	if f != nil {
		if f.NumFields() > 1 {
			p = &parma{}
			d := f.List[n].Type
			switch exp := d.(type) {
			case *ast.SelectorExpr: // 非本文件包
				p.Type = exp.Sel.Name
				if x, ok := exp.X.(*ast.Ident); ok {
					p.Import = imports[x.Name]
					p.Pkg = gast.GetImportPkg(p.Import)
				}
			case *ast.StarExpr: // 本文件
				switch expx := exp.X.(type) {
				case *ast.SelectorExpr: // 非本地包
					p.Type = expx.Sel.Name
					if x, ok := expx.X.(*ast.Ident); ok {
						p.Pkg = x.Name
						p.Import = imports[p.Pkg]
					}
				case *ast.Ident: // 本文件
					p.Type = expx.Name
					p.Import = objPkg // 本包
				default:
					glog.ErrorString(fmt.Sprintf("not find any expx.(%v) [%v]", reflect.TypeOf(expx), objPkg))
				}
			case *ast.Ident: // 本文件
				p.Type = exp.Name
				p.Import = objPkg // 本包
			default:
				glog.ErrorString(fmt.Sprintf("not find any exp.(%v) [%v]", reflect.TypeOf(d), objPkg))
			}
		}
	}

	if p != nil {
		if len(p.Pkg) > 0 {
			var pkg string
			n := strings.LastIndex(p.Import, "/")
			if n > 0 {
				pkg = p.Import[n+1:]
			}
			if len(pkg) > 0 {
				p.Pkg = pkg
			}
		}
	}
	return
}
var replace *strings.Replacer
// UnMarshal  回退网络模式
func UnMarshal(name string) string {
	const (
		lower = false
		upper = true
	)

	if name == "" {
		return ""
	}

	var (
		value                                    = replace.Replace(name)
		buf                                      = bytes.NewBufferString("")
		lastCase, currCase, nextCase, nextNumber bool
	)

	for i, v := range value[:len(value)-1] {
		nextCase = bool(value[i+1] >= 'A' && value[i+1] <= 'Z')
		nextNumber = bool(value[i+1] >= '0' && value[i+1] <= '9')

		if i > 0 {
			if currCase == upper {
				if lastCase == upper && (nextCase == upper || nextNumber == upper) {
					buf.WriteRune(v)
				} else {
					if value[i-1] != '_' && value[i+1] != '_' {
						buf.WriteRune('_')
					}
					buf.WriteRune(v)
				}
			} else {
				buf.WriteRune(v)
				if i == len(value)-2 && (nextCase == upper && nextNumber == lower) {
					buf.WriteRune('_')
				}
			}
		} else {
			currCase = upper
			buf.WriteRune(v)
		}
		lastCase = currCase
		currCase = nextCase
	}
	buf.WriteByte(value[len(value)-1])
	s := strings.ToLower(buf.String())
	return s
}




// 返回默认的注解
func (b *Base) defaultAnnotation(objName, objFunc string, num int) (routerPath string, methods []string) {
	methods = []string{"ANY"}
	if num == 2 { // parma 2 , post default
		methods = []string{"post"}
	}
	if b.isBigCamel { // big camel style.大驼峰
		routerPath = objName + "." + objFunc
	} else {
		routerPath = UnMarshal(objName) + "." + UnMarshal(objFunc)
	}
	return
}

// 解析路由注解
func (b *Base) parseAnnotation(f *ast.FuncDecl, objName, objFunc string, imports map[string]string, objPkg string, num int) ([]annotation, *parma, *parma) {
	var note string
	var gcs []annotation
	req := isParma(f.Type.Params, imports, objPkg, 1)
	resp := isParma(f.Type.Results, imports, objPkg, 0)

	if f.Doc != nil {
		for _, c := range f.Doc.List {
			gc := annotation{}
			t := strings.TrimSpace(strings.TrimPrefix(c.Text, "//"))
			if strings.HasPrefix(t, "@Router") {
				matches := routeRegex.FindStringSubmatch(t)
				if len(matches) == 3 {
					gc.RouterPath = matches[1]
					methods := matches[2]
					if methods == "" {
						gc.Methods = []string{"get"}
					} else {
						gc.Methods = strings.Split(methods, ",")
					}
					gcs = append(gcs, gc)
				}
			} else if strings.HasPrefix(t, objFunc) { // find note
				t = strings.TrimSpace(strings.TrimPrefix(t, objFunc))
				note += t
			}
		}

	}

	if len(gcs) == 0 {
		gc := annotation{}
		gc.RouterPath, gc.Methods = b.defaultAnnotation(objName, objFunc, num)
		gcs = append(gcs, gc)
	}

	for i := 0; i < len(gcs); i++ {	// add note 添加注释
		gcs[i].Note = note
	}
	return gcs, req, resp
}

func (b *Base) parserStruct(req, resp *parma, astPkg *ast.Package, modPkg, modFile string) (r, p *gdoc.StructInfo) {
	ant := gast.NewAnyStruct(modPkg, modFile)

	if req != nil {
		tmp := astPkg
		if len(req.Pkg) > 0 {
			objFile := gast.EvalSymlinks(modPkg, modFile, req.Import)
			tmp, _ = gast.GetAstPkg(req.Pkg, objFile) // get ast trees.
		}
		r = ant.ParserStruct(tmp, req.Type)
	}

	if resp != nil {
		tmp := astPkg
		if len(resp.Pkg) > 0 {
			objFile := gast.EvalSymlinks(modPkg, modFile, resp.Import)
			tmp, _ = gast.GetAstPkg(resp.Pkg, objFile) // get ast trees.
		}
		p = ant.ParserStruct(tmp, resp.Type)
	}
	return
}

// tryRegister gen out the Registered config info  by struct object,[prepath + bojname.]
func (b *Base) tryRegister(router IRoute, cList []interface{}) bool {
	modPkg, modFile, isFind := gast.GetModel(2)
	if !isFind {
		return false
	}

	groupPath := b.BasePath(router)
	doc := gdoc.NewDoc(groupPath)

	for _, c := range cList {
		refVal := reflect.ValueOf(c)
		t := reflect.Indirect(refVal).Type()
		objPkg := t.PkgPath()
		objName := t.Name()
		// fmt.Println(objPkg, objName)

		// find path
		objFile := gast.EvalSymlinks(modPkg, modFile, objPkg)
		// fmt.Println(objFile)

		astPkg, _b := gast.GetAstPkg(objPkg, objFile) // get ast trees.
		if _b {
			imports := gast.AnalysisImport(astPkg)
			funMp := gast.GetObjFunMp(astPkg, objName)
			// ast.Print(token.NewFileSet(), astPkgs)
			// fmt.Println(b)

			refTyp := reflect.TypeOf(c)
			// Install the methods
			for m := 0; m < refTyp.NumMethod(); m++ {
				method := refTyp.Method(m)
				num, _b := b.checkHandlerFunc(method.Type , true)
				if _b {
					if sdl, ok := funMp[method.Name]; ok {
						gcs, req, resp := b.parseAnnotation(sdl, objName, method.Name, imports, objPkg, num)
						if b.isOutDoc { // output doc
							docReq, docResp := b.parserStruct(req, resp, astPkg, modPkg, modFile)
							for _, gc := range gcs {
								doc.AddOne(objName, gc.RouterPath, gc.Methods, gc.Note, docReq, docResp)
							}
						}
						for _, gc := range gcs {
							checkOnceAdd(objName+"."+method.Name, gc.RouterPath, gc.Methods)
						}
					}
				}
			}
		}
	}

	if b.isOutDoc {
		doc.GenSwagger(modFile + "/docs/swagger/")
		doc.GenMarkdown(modFile + "/docs/markdown/")
	}
	genOutPut(b.outPath, modFile) // generate code
	return true
}


// register Registered by struct object,[prepath + bojname.]
func (b *Base) register(router IRoute, cList ...interface{}) bool {
	// groupPath := b.BasePath(router)
	list := getInfo()
	for _, c := range cList {
		refTyp := reflect.TypeOf(c)
		refVal := reflect.ValueOf(c)
		t := reflect.Indirect(refVal).Type()
		objName := t.Name()

		// Install the methods
		for m := 0; m < refTyp.NumMethod(); m++ {
			method := refTyp.Method(m)
			num, _b := b.checkHandlerFunc(method.Type , true)
			if _b {
				if v, ok := list[objName+"."+method.Name]; ok {
					for _, v1 := range v {
						b.registerObj(router, v1.Annotation.Methods, v1.Annotation.RouterPath, method.Name, method.Func, refVal)
					}
				} else { // not find using default case
					routerPath, methods := b.defaultAnnotation(objName, method.Name, num)
					b.registerObj(router, methods, routerPath, method.Name, method.Func, refVal)
				}
			}
		}
	}
	return true
}

// registerObj 获取并过滤要绑定的参数(注册处理器对象)
func (b *Base) registerObj(router IRoute, httpMethod []string, relativePath, methodName string, tvl, obj reflect.Value) error {
	call := b.handlerFuncObj(tvl, obj, methodName)

	for _, v := range httpMethod {
		switch strings.ToUpper(v) {
		case "POST":
			router.POST(relativePath, call)
		case "GET":
			router.GET(relativePath, call)
		case "DELETE":
			router.DELETE(relativePath, call)
		case "PATCH":
			router.PATCH(relativePath, call)
		case "PUT":
			router.PUT(relativePath, call)
		case "OPTIONS":
			router.OPTIONS(relativePath, call)
		case "HEAD":
			router.HEAD(relativePath, call)
		case "ANY":
			router.Any(relativePath, call)
		default:
			return gerror.Errorf("method:[%v] not support", httpMethod)
		}
	}
	return nil
}


// HandlerFunc 获取并过滤要绑定的参数(obj 对象类型)
func (b *Base) handlerFuncObj(tvl, obj reflect.Value, methodName string) HandlerFunc {
	typ := tvl.Type()
	if typ.NumIn() == 2 { // 参数检查
		ctxType := typ.In(1)

		apiFun := func(c *Context) interface{} { return c }//gin默认的方法
		if ctxType == b.apiType { //自定义的context
			apiFun = b.apiFunc
		} else if !(ctxType == reflect.TypeOf(&Context{})) {
			panic("method " + runtime.FuncForPC(tvl.Pointer()).Name() + " not support!")
		}

		return func(c *Context) {
			defer func() {
				if err := recover(); err != nil {
					b.errorFunc(err)
				}
			}()
			tvl.Call([]reflect.Value{obj, reflect.ValueOf(apiFun(c))})
		}
	}

	call, err := b.callObj(tvl, obj, methodName)// 自定义的context类型,带request 请求参数
	if err != nil { // Direct reporting error.
		panic(err)
	}
	return call
}

// Custom context type with request parameters
func (b *Base) callObj(tvl, obj reflect.Value, methodName string) (func(*Context), error) {
	typ := tvl.Type()
	if typ.NumIn() != 3 { // 参数检查
		return nil, gerror.New("method " + runtime.FuncForPC(tvl.Pointer()).Name() + " not support!")
	}

	if typ.NumOut() != 0 {
		if typ.NumOut() == 2 { // 参数检查
			if returnType := typ.Out(1); returnType != typeOfError {
				return nil, gerror.Errorf("method : %v , returns[1] %v not error",
					runtime.FuncForPC(tvl.Pointer()).Name(), returnType.String())
			}
		} else {
			return nil, gerror.Errorf("method : %v , Only 2 return values (obj, error) are supported", runtime.FuncForPC(tvl.Pointer()).Name())
		}
	}

	ctxType, reqType := typ.In(1), typ.In(2)
	reqIsGinCtx := false

	if ctxType == reflect.TypeOf(&Context{}) {
		reqIsGinCtx = true
	}

	if !reqIsGinCtx && ctxType != b.apiType && !b.apiType.ConvertibleTo(ctxType) {
		return nil, gerror.New("method " + runtime.FuncForPC(tvl.Pointer()).Name() + " first parma not support!")
	}

	reqIsValue := true
	if reqType.Kind() == reflect.Ptr {
		reqIsValue = false
	}

	apiFun := func(c *Context) interface{} { return c }
	if !reqIsGinCtx {
		apiFun = b.apiFunc
	}

	return func(c *Context) {
		defer func() {
			if err := recover(); err != nil {
				b.errorFunc(err)
			}
		}()

		req := reflect.New(reqType)
		if !reqIsValue {
			req = reflect.New(reqType.Elem())
		}
		if err := b.unmarshal(c, req.Interface()); err != nil { // Return error message.返回错误信息
			b.handleError(c, req, err)
			return
		}

		if reqIsValue {
			req = req.Elem()
		}

		res, is := b.before(c, tvl, obj, req.Interface(), methodName)
		if !is {
			c.JSON(http.StatusBadRequest, res.Response)
			return
		}

		var returnValues []reflect.Value
		returnValues = tvl.Call([]reflect.Value{obj, reflect.ValueOf(apiFun(c)), req})

		if returnValues != nil {
			res.Response = returnValues[0].Interface()
			rerr := returnValues[1].Interface()
			if rerr != nil {
				res.Error = rerr.(error)
			}
			is = b.after(res, obj)
			if is {
				c.JSON(http.StatusOK, res.Response)
			} else {
				c.JSON(http.StatusBadRequest, res.Response)
			}
		}
	}, nil
}

func (b *Base) unmarshal(c *Context, v interface{}) error {
	return c.Parse(v)
}

// FindTag find struct of tag string.查找struct 的tag信息
func FindTag(obj interface{}, field, tag string) string {
	dataStructType := reflect.Indirect(reflect.ValueOf(obj)).Type()
	for i := 0; i < dataStructType.NumField(); i++ {
		fd := dataStructType.Field(i)
		if fd.Name == field {
			bb := fd.Tag
			sqlTag := bb.Get(tag)

			if sqlTag == "-" || bb == "-" {
				return ""
			}

			sqlTags := strings.Split(sqlTag, ",")
			sqlFieldName := fd.Name // default
			if len(sqlTags[0]) > 0 {
				sqlFieldName = sqlTags[0]
			}
			return sqlFieldName
		}
	}

	return ""
}

func (b *Base) handleError(c *Context, req reflect.Value, err error) {
	var fields []string
	if _, ok := err.(validator.ValidationErrors); ok {
		for _, err := range err.(validator.ValidationErrors) {
			tmp := fmt.Sprintf("%v:%v", FindTag(req.Interface(), err.Field(), "json"), err.Tag())
			if len(err.Param()) > 0 {
				tmp += fmt.Sprintf("[%v](but[%v])", err.Param(), err.Value())
			}
			fields = append(fields, tmp)
		}
	} else if _, ok := err.(*json.UnmarshalTypeError); ok {
		err := err.(*json.UnmarshalTypeError)
		tmp := fmt.Sprintf("%v:%v(but[%v])", err.Field, err.Type.String(), err.Value)
		fields = append(fields, tmp)

	} else {
		fields = append(fields, err.Error())
	}

	msg := msg.GetErrorMsg(msg.ParameterInvalid)
	msg.Error = fmt.Sprintf("req param : %v", strings.Join(fields, ";"))
	c.JSON(http.StatusBadRequest, msg)
	return
}

func (b *Base) before(c *Context, tvl, obj reflect.Value, req interface{}, methodName string) (*BeforeAfter, bool) {
	res := &BeforeAfter{
		C:        c,
		FuncName: fmt.Sprintf("%v.%v", reflect.Indirect(obj).Type().Name(), methodName), // 函数名
		Param:    req,                                                                   // 调用前的请求参数
		Ctx:      context.Background(),                                                  // 占位参数，可用于存储其他参数，前后连接可用
	}
	is := true
	if v, ok := obj.Interface().(Hook); ok { // 本类型
		is = v.Before(res)
	}
	if is && b.beforeAfter != nil {
		is = b.beforeAfter.Before(res)
	}
	return res, is
}

func (b *Base) after(info *BeforeAfter, obj reflect.Value) bool {
	is := true
	if v, ok := obj.Interface().(Hook); ok { // 本类型
		is = v.After(info)
	}
	if is && b.beforeAfter != nil {
		is = b.beforeAfter.After(info)
	}
	return is
}
*/
